﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using System.Reflection;
using System.Runtime.Serialization;

namespace System
{
	public sealed class NodeCollection<T> : IList<T>, IList, ICloneable
	{
		private object syncRoot;
		private object parentNode;
		private List<T> list;
		private PropertyInfo parentProperty;

		public event EventHandler<EventArgs<T>> Added;
		public event EventHandler<EventArgs<T>> Removed;

		public NodeCollection()
		{
			this.syncRoot = new Object();
			this.list = new List<T>();
			this.parentProperty = ParentNodeManager.GetParentNode(typeof(T));
		}

		public NodeCollection(object parentNode)
			: this()
		{
			this.parentNode = parentNode;
		}

		private void FireEvent(EventHandler<EventArgs<T>> evt, T item)
		{
			if (evt == Added)
			{
				if (parentProperty != null)
				{
					parentProperty.SetValue(item, parentNode, null);
				}
			}

			if (evt != null)
			{
				evt(this, new EventArgs<T>(item));
			}
		}

		public void AddRange(IEnumerable<T> collection)
		{
			list.AddRange(collection);

			foreach (T obj in collection)
			{
				FireEvent(Added, obj);
			}
		}

		public bool ContaineID(string id)
		{
			foreach (object node in this.list)
			{
				if (node != null && node is Node)
				{
					if (((Node)node).ID.Equals(id))
					{
						return true;
					}
				}
			}

			return false;
		}

		public bool ContaineName(string name)
		{
			foreach (object node in this.list)
			{
				if (node != null && node is Node)
				{
					if (((Node)node).Name.Equals(name))
					{
						return true;
					}
				}
			}

			return false;
		}

		public T FindElementByID(string id)
		{
			foreach (object obj in this.list)
			{
				if (obj != null && obj is Node)
				{
					var node = (Node)obj;
					if (string.IsNullOrEmpty(node.ID))
					{
						continue;
					}

					if (node.ID.Equals(id))
					{
						return (T)obj;
					}
				}
			}

			return default(T);
		}

		public T FindElementByName(string name)
		{
			foreach (object obj in this.list)
			{
				if (obj != null && obj is Node)
				{
					Node node = (Node)obj;
					if (string.IsNullOrEmpty(node.Name))
					{
						continue;
					}

					if (node.Name.Equals(name))
					{
						return (T)obj;
					}
				}
			}

			return default(T);
		}

		public NodeCollection<T> Clone()
		{
			bool canClone = typeof(T).GetInterface(typeof(ICloneable).FullName, false) != null;

			NodeCollection<T> list = new NodeCollection<T>();
			foreach (var item in this)
			{
				if (canClone)
				{
					list.Add((item as ICloneable).Clone());
				}
				else
				{
					T newItem = Activator.CreateInstance<T>();
					ObjectUtility.CopyProperties(item, newItem);

					list.Add(newItem);
				}
			}

			return list;
		}

		#region IList<T> Members

		public int IndexOf(T item)
		{
			return list.IndexOf(item);
		}

		public void Insert(int index, T item)
		{
			list.Insert(index, item);

			FireEvent(Added, item);
		}

		public void RemoveAt(int index)
		{
			if (index < list.Count)
			{
				T item = list[index];
				list.RemoveAt(index);

				FireEvent(Removed, item);
			}
		}

		public T this[int index]
		{
			get
			{
				return list[index];
			}
			set
			{
				list[index] = value;
			}
		}

		#endregion

		#region ICollection<T> Members

		public void Add(T item)
		{
			list.Add(item);

			FireEvent(Added, item);
		}

		public void Clear()
		{
			T[] items = list.ToArray();

			foreach (T item in items)
			{
				Remove(item);
			}
		}

		public bool Contains(T item)
		{
			return list.Contains(item);
		}

		public void CopyTo(T[] array, int arrayIndex)
		{
			list.CopyTo(array, arrayIndex);
		}

		public int Count
		{
			get { return list.Count; }
		}

		public bool IsReadOnly
		{
			get { return true; }
		}

		public bool Remove(T item)
		{
			bool removed = list.Remove(item);

			if (removed)
			{
				FireEvent(Removed, item);
			}

			return removed;
		}

		#endregion

		#region IEnumerable<T> Members

		public IEnumerator<T> GetEnumerator()
		{
			return list.GetEnumerator();
		}

		#endregion

		#region IEnumerable Members

		System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
		{
			return list.GetEnumerator();
		}

		#endregion

		#region IList Members

		public int Add(object value)
		{
			Add((T)value);
			return this.Count - 1;
		}

		public bool Contains(object value)
		{
			return Contains((T)value);
		}

		public int IndexOf(object value)
		{
			return IndexOf((T)value);
		}

		public void Insert(int index, object value)
		{
			Insert(index, (T)value);
		}

		public bool IsFixedSize
		{
			get { return true; }
		}

		public void Remove(object value)
		{
			Remove((T)value);
		}

		object IList.this[int index]
		{
			get
			{
				return this[index];
			}
			set
			{
				this[index] = (T)value;
			}
		}

		#endregion

		#region ICollection Members

		public void CopyTo(Array array, int index)
		{
			list.ToArray().CopyTo(array, index);
		}

		public bool IsSynchronized
		{
			get { return true; }
		}

		public object SyncRoot
		{
			get { return syncRoot; }
		}

		#endregion

		#region ICloneable Members

		object ICloneable.Clone()
		{
			return this.Clone();
		}

		#endregion
	}
}
